//////////////////////////////////////////////////////
//project: sram controller
//name: sram_ctrl
//designer: qianyw
//ver     0.1
//date:   2014_06_05 
//description:
//         sram MODLE:IS61WV1024-10
//         fclk is 1M
//         rst_n, reset signal, low active
//         sram_oe, the module enable signal
//         addr_in, the address which to read and write
//         sram_data_in, the data which to write
//         data_out, the data which to read
//         ack, when the ack is high, the data is avaliable
module sram_ctrl( //input
		  clk_1m,
		  rst_n,
		  wr,
		  rd,
		  addr_in,
		  sram_oe,
		  sram_data_in,
		  //output
		  sram_ctrl_addr,
		  data_out,
		  ack,
		  busy,
		  n_sram_we,//to sram in fpga
		  n_sram_ce,//to sram in fpga
		  n_sram_oe,//to sram in fpga
		  n_sram_lb,//to sram in fpga
		  n_sram_ub,//to sram in fpga
		  //inout
		  sram_dq//to sram in fpga
		 );
		 
input        clk_1m,
	 rst_n,
	 wr,
	 sram_oe,
	 rd;

input[7:0]   sram_data_in;
input[12:0]  addr_in;
output       n_sram_we,
	 n_sram_ce,
	 n_sram_oe,
	 n_sram_lb,
	 n_sram_ub,
	 busy,
	 ack;
output[7:0] data_out;
output[17:0] sram_ctrl_addr;
inout[15:0]  sram_dq;

parameter    IDLE = 2'd0,
			 RD0 = 2'd1,
			 LATCH = 2'd2,
			 WR0 = 2'd3;
	
	 
reg       	 n_we_reg,
	 ack_reg,
	 n_ce_reg,
	 n_oe_reg,
	 n_lb_reg,
	 n_ub_reg;
reg[17:0]    sram_addr_reg;
reg[7:0]    data_out_reg;
reg[15:0]		     sram_dq_reg;
reg[1:0]     state,
	 nstate;

assign ack = ack_reg;
assign n_sram_we = n_we_reg;
assign n_sram_ce = n_ce_reg;
assign n_sram_oe = n_oe_reg;
assign n_sram_lb = n_lb_reg;
assign n_sram_ub = n_ub_reg;
assign sram_ctrl_addr = sram_addr_reg;
assign data_out = data_out_reg;
assign sram_dq = (state == WR0) ? sram_dq_reg: 16'hzzzz;
assign busy = state != IDLE;

always @(posedge clk_1m) begin
if(rst_n == 1'b0)
state <= IDLE;
else if(sram_oe == 1'b0)
state <= IDLE;
else
state <= nstate;
end

always @(*) begin
if(rst_n == 1'b0)
nstate = IDLE;
else if(sram_oe == 1'b0)
nstate = IDLE;
else begin
case(state)
	IDLE: begin
		if(rd)
			nstate = RD0;
		else if(wr)
			nstate = WR0;
		else
			nstate = IDLE;
	end
	RD0: begin
		nstate = LATCH;
	end
	LATCH: begin
		nstate = IDLE;
	end
	WR0: begin
		nstate = IDLE;
	end
	default: begin
		nstate = IDLE;
	end
endcase
end
end

always @(posedge clk_1m) begin
if(rst_n == 1'b0) begin
n_we_reg <= 1'b1;
n_ce_reg <= 1'b1;
n_oe_reg <= 1'b1;
n_lb_reg <= 1'b1;
n_ub_reg <= 1'b1;
data_out_reg <= 8'd0;
ack_reg <= 1'b0;
sram_addr_reg <= 18'd0;	
end
else if(sram_oe == 1'b0) begin
n_we_reg <= 1'b1;
n_ce_reg <= 1'b1;
n_oe_reg <= 1'b1;
n_lb_reg <= 1'b1;
n_ub_reg <= 1'b1;
 ack_reg <= 1'b0;
data_out_reg <= 8'd0;
sram_addr_reg <= 18'd0;
end
else begin
case(nstate)
	IDLE: begin
		n_we_reg <= 1'b1;
		n_ce_reg <= 1'b1;
		n_oe_reg <= 1'b1;
		n_lb_reg <= 1'b1;
		n_ub_reg <= 1'b1;  
		ack_reg <= 1'b0;			
		//sram_addr_reg <= {{6{1'b0}},addr_in[12:1]};	
	end
	RD0: begin
		n_we_reg <= 1'b1;
		n_ce_reg <= 1'b0;
		n_oe_reg <= 1'b0;
		n_lb_reg <= addr_in[0];
		n_ub_reg <= (~addr_in[0]);
		sram_addr_reg <= {{6{1'b0}},addr_in[12:1]};	
	end
	LATCH: begin
		n_we_reg <= 1'b1;
		n_ce_reg <= 1'b1;
		n_oe_reg <= 1'b1;
		n_lb_reg <= 1'b1;
		n_ub_reg <= 1'b1;  	
		ack_reg <= 1'b1;
		data_out_reg <= (addr_in[0]) ? sram_dq[15:8] : sram_dq[7:0];
	end
	WR0: begin
		n_we_reg <= 1'b0;
		n_ce_reg <= 1'b0;
		n_oe_reg <= 1'b0;
		n_lb_reg <= addr_in[0];
		n_ub_reg <= ~addr_in[0];
		sram_addr_reg <= {{6{1'b0}},addr_in[12:1]};
		ack_reg <= 1'b1;
		sram_dq_reg <= addr_in[0] ? {sram_data_in, sram_dq_reg[7:0]}:{sram_dq_reg[15:8],sram_data_in};
			end
		endcase
    end
end
endmodule
//state[3:0] -> state[2:0]
